#ifndef CALENDARMODEL_H
#define CALENDARMODEL_H

#include <QAbstractTableModel>
#include <QDateTime>
#include <QMap>
#include "Event.h"

typedef QList<Qt::DayOfWeek> WeekendList_t;

class CalendarModel : public QAbstractTableModel
{
    Q_OBJECT
public:
    friend class TestCalendarModel;

    enum HORIZONTAL_HEADER_FORMAT {
        NO_HORIZONTAL_HEADER,
        SINGLE_LETTER_DAY_NAMES,
        SHORT_DAY_NAMES,
        LONG_DAY_NAMES,
    };

    enum CALENDAR_CELL_DATA {
        DATE = Qt::UserRole + 1,
        DAY_OF_WEEK,
        WEEK,
        DAY_OF_ANOTHER_MONTH,
        WEEKEND,
        SHORT_WORK_DAY,
        EVENT,
        EVENT_COUNT,
    };

    explicit CalendarModel(QObject *parent = 0);

    inline int rowCount(const QModelIndex &) const { return m_firstRow + ROW_COUNT; }
    inline int rowCount() const { return rowCount(QModelIndex()); }
    inline int columnCount(const QModelIndex &) const { return m_firstColumn + COLUMN_COUNT; }
    inline int columnCount() const { return columnCount(QModelIndex()); }
    QVariant data(const QModelIndex &index, int role) const;
    inline bool insertRows(int row, int count, const QModelIndex &parent = QModelIndex())
    {
        beginInsertRows(parent, row, row + count - 1);
        endInsertRows();
        return true;
    }
    inline bool insertColumns(int column, int count, const QModelIndex &parent = QModelIndex())
    {
        beginInsertColumns(parent, column, column + count - 1);
        endInsertColumns();
        return true;
    }
    inline bool removeRows(int row, int count, const QModelIndex &parent = QModelIndex())
    {
        beginRemoveRows(parent, row, row + count - 1);
        endRemoveRows();
        return true;
    }
    inline bool removeColumns(int column, int count, const QModelIndex &parent = QModelIndex())
    {
        beginRemoveColumns(parent, column, column + count - 1);
        endRemoveColumns();
        return true;
    }

    void showMonth(int year, int month);
    void internalUpdate();
    void updateMonthSchedule();
    QDate referenceDate() const;
    QDate dateForCell(int row, int column) const;
    QModelIndex cellForDate(const QDate &date) const;
    int columnForFirstOfMonth(const QDate &date) const;
    int columnForDayOfWeek(Qt::DayOfWeek day) const;

    Qt::DayOfWeek dayOfWeekForColumn(int section) const;
    QString dayName(Qt::DayOfWeek day) const;

    int firstColumn() const { return m_firstColumn; }
    int firstRow() const { return m_firstRow; };
    bool isHorizontalHeader(int row, int column) const;
    bool isVerticalHeader(int row, int column) const;

    // управление:
    void showNextMonth();
    void showPrevMonth();
    void showNextYear();
    void showPrevYear();

    // настройки:
    void setDate(const QDate &date);
    void setMinimumDate(const QDate &date);
    void setMaximumDate(const QDate &date);
    void setFirstColumnDay(Qt::DayOfWeek dayOfWeek);
    void setHorizontalHeaderFormat(HORIZONTAL_HEADER_FORMAT format);
    void setWeekNumbersShown(bool shown);

    inline QDate date() const { return m_date; }
    inline QDate minimumDate() const { return m_minimumDate; }
    inline QDate maximumDate() const { return m_maximumDate; }
    inline int shownYear() const { return m_shownYear; }
    inline int shownMonth() const { return m_shownMonth; }
    inline Qt::DayOfWeek firstColumnDay() const { return m_firstDay; }
    inline HORIZONTAL_HEADER_FORMAT horizontalHeaderFormat() const { return m_horizontalHeaderFormat; }
    inline bool isWeekNumbersShown() const { return m_isWeekNumbersShown; }

private:
    enum {
        ROW_COUNT = 6,
        COLUMN_COUNT = 7,
        HEADER_ROW = 0,
        HEADER_COLUMN = 0,
        MIN_DAY_OFFSET = 0
    };

    int m_firstColumn;
    int m_firstRow;
    QDate m_date;
    QDate m_minimumDate;
    QDate m_maximumDate;
    int m_shownYear;
    int m_shownMonth;
    Qt::DayOfWeek m_firstDay;
    HORIZONTAL_HEADER_FORMAT m_horizontalHeaderFormat;
    bool m_isWeekNumbersShown;
    WeekendList_t m_weekendList;
    EventList_t m_monthSchedule;
};

#endif // CALENDARMODEL_H
